﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using Microsoft.Win32;
using System.IO;
using System.Runtime.InteropServices;

namespace ProjectResistance
{
    internal static class CurrentDevice
    {
        private const int MAX_PATH = 260;
        private const string MicrosoftEmulatorOemValue = "Microsoft DeviceEmulator";
        private const string DLL_NAME = "coredll.dll";
        private const string TOUCH_DRIVER_KEY = @"HKEY_LOCAL_MACHINE\Hardware\DeviceMap\Touch";
        private const string TOUCH_DRIVER_VALUE = "DriverName";
        private const string SMARTPHONE = "SmartPhone";
        private const string PPC = "PocketPC";

        [DllImport(DLL_NAME, SetLastError=true)]
        private static extern int SHGetSpecialFolderPath(IntPtr hwndOwner, StringBuilder lpszPath, int nFolder, int fCreate);

        [DllImport(DLL_NAME, SetLastError = true, EntryPoint = "SystemParametersInfoW", CharSet = CharSet.Unicode)]
        private static extern int SystemParametersInfo(uint uiAction, uint uiParam, StringBuilder pvParam, uint fWinIni);

        // value caches
        private static bool? m_hasTouch;
        private static string m_platformType;
        private static string m_oemInfo;

        private enum SpecialFolders : int
        {
            CSIDL_WINDOWS = 0x0024,
        }

        private enum SystemParametersInfoActions : uint
        {
            SPI_GETPLATFORMTYPE = 257, // this is used elsewhere for Smartphone/PocketPC detection
            SPI_GETOEMINFO = 258,
        }

        private static string GetSpecialFolder(SpecialFolders specialFolder)
        {
            StringBuilder path = new StringBuilder(MAX_PATH);

            if (SHGetSpecialFolderPath(IntPtr.Zero, path, (int)specialFolder, 0) == 0)
            {
                throw new Exception("Error getting Windows path.");
            }

            return path.ToString();
        }

        private static string PlatformType
        {
            get
            {
                if (m_platformType == null)
                {
                    StringBuilder platformType = new StringBuilder(50);

                    if (SystemParametersInfo(
                        (uint)SystemParametersInfoActions.SPI_GETPLATFORMTYPE,
                        (uint)platformType.Capacity,
                        platformType,
                        0) == 0)
                    {
                        throw new Exception("Error getting platform type.");
                    }

                    m_platformType = platformType.ToString();
                }

                return m_platformType;
            }
        }

        private static string OemInfo
        {
            get
            {
                if (m_oemInfo == null)
                {
                    StringBuilder oemInfo = new StringBuilder(50);

                    if (SystemParametersInfo(
                        (uint)SystemParametersInfoActions.SPI_GETOEMINFO,
                        (uint)oemInfo.Capacity, oemInfo, 0) == 0)
                    {
                        throw new Exception("Error getting OEM info.");
                    }

                    m_oemInfo = oemInfo.ToString();
                }
                return m_oemInfo;
            }
        }

        public static bool IsEmulator()
        {
            return OemInfo == MicrosoftEmulatorOemValue;
        }

        public static bool HasTouchScreen
        {
            get
            {
                if (!m_hasTouch.HasValue)
                {
                    string driverFileName = Registry.GetValue(TOUCH_DRIVER_KEY, TOUCH_DRIVER_VALUE, "touch.dll").ToString();
                    string windowsFolder = GetSpecialFolder(SpecialFolders.CSIDL_WINDOWS);
                    string driverPath = Path.Combine(windowsFolder, driverFileName);
                    bool driverExists = File.Exists(driverPath);

                    // Windows Mobile 5.0 Smartphone emulator and earlier has a driver, but no touch screen.
                    m_hasTouch = ((driverExists) && !(IsSmartphone() && IsEmulator() && Environment.OSVersion.Version.Major < 6));
                }

                return m_hasTouch.Value;
            }
        }

        public static bool IsSmartphone()
        {
            return PlatformType == SMARTPHONE;
        }

        public static bool IsPocketPC()
        {
            return PlatformType == PPC;
        }
    }
}
